package conversion

import (
	"encoding/json"
	"fmt"
	"gitee.com/filters/utils/config"
	"github.com/go-redis/redis/v8"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"reflect"
)

// ToString 转换为字符串
func ToString(info interface{}) string {
	infoString, _ := json.Marshal(info)
	return string(infoString)
}

// ToByte 转换为字节
func ToByte(info interface{}) []byte {
	infoString, _ := json.Marshal(info)
	return infoString
}

// ComboBuilder 配置绑定构建器
type ComboBuilder struct {
	targets    []interface{}
	configFile string
}

// BindCombo 创建配置绑定构建器
func BindCombo(targets ...interface{}) *ComboBuilder {
	return &ComboBuilder{
		targets: targets,
	}
}

// WithConfigFile 设置配置文件路径，如果不传参数则使用默认配置文件
func (cb *ComboBuilder) WithConfigFile(configFile ...string) *ComboBuilder {
	if len(configFile) > 0 && configFile[0] != "" {
		cb.configFile = configFile[0]
	} else {
		// 使用默认配置文件路径
		cb.configFile = "config.yaml"
	}
	return cb
}

// Build 执行配置绑定
func (cb *ComboBuilder) Build() error {
	if cb.configFile == "" {
		// 如果没有设置配置文件，使用默认配置文件
		cb.configFile = "config.yaml"
	}

	// 使用 config 包的 ConfigReader 读取配置文件
	reader := config.NewConfigReader(cb.configFile)
	configData, err := reader.GetAllConfig()
	if err != nil {
		return fmt.Errorf("failed to read config file: %v", err)
	}
	// 绑定每个目标结构体
	for _, target := range cb.targets {
		if err := cb.bindTarget(target, configData); err != nil {
			return err
		}
	}
	return nil
}

// bindTarget 绑定单个目标结构体
func (cb *ComboBuilder) bindTarget(target interface{}, config map[string]interface{}) error {
	targetValue := reflect.ValueOf(target)
	if targetValue.Kind() != reflect.Ptr || targetValue.Elem().Kind() != reflect.Struct {
		return fmt.Errorf("target must be a pointer to struct")
	}

	targetStruct := targetValue.Elem()
	targetType := targetStruct.Type()

	for i := 0; i < targetStruct.NumField(); i++ {
		field := targetStruct.Field(i)
		fieldType := targetType.Field(i)

		// 获取confx标签
		confxTag := fieldType.Tag.Get("confx")
		if confxTag == "" {
			continue
		}

		// 解析confx标签
		tagInfo := parseConfxTag(confxTag)
		if tagInfo.Name == "" && tagInfo.Format == "" {
			continue
		}

		// 根据字段类型进行绑定
		if err := cb.bindField(field, fieldType, tagInfo, config); err != nil {
			return fmt.Errorf("failed to bind field %s: %v", fieldType.Name, err)
		}
	}

	return nil
}

// ConfxTag confx标签信息
type ConfxTag struct {
	Name   string
	Format string
}

// parseConfxTag 解析confx标签
func parseConfxTag(tag string) ConfxTag {
	result := ConfxTag{}

	// 解析 name=xxx 格式
	if len(tag) > 5 && tag[:5] == "name=" {
		result.Name = tag[5:]
	}

	// 解析 format=xxx 格式
	if len(tag) > 7 && tag[:7] == "format=" {
		result.Format = tag[7:]
		// 对于 format=json 的情况，Name 字段留空，在 bindTarget 中会跳过 Name 检查
	}

	return result
}

// bindField 绑定单个字段
func (cb *ComboBuilder) bindField(field reflect.Value, fieldType reflect.StructField, tagInfo ConfxTag, config map[string]interface{}) error {
	if !field.CanSet() {
		return fmt.Errorf("field %s cannot be set", fieldType.Name)
	}

	// 根据字段类型进行不同的绑定处理
	switch fieldType.Type {
	case reflect.TypeOf((*redis.Client)(nil)):
		return cb.bindRedisClient(field, tagInfo, config)
	case reflect.TypeOf((*gorm.DB)(nil)):
		return cb.bindGormDB(field, tagInfo, config)
	default:
		// 处理其他类型，如配置结构体
		if tagInfo.Format == "json" {
			return cb.bindJSONConfig(field, fieldType, tagInfo, config)
		}
	}

	return nil
}

// bindRedisClient 绑定Redis客户端
func (cb *ComboBuilder) bindRedisClient(field reflect.Value, tagInfo ConfxTag, config map[string]interface{}) error {
	// 尝试获取 redis 配置，支持多种类型
	var redisConfigs map[string]interface{}

	if redisConfigsInterface, ok := config["redis"].(map[string]interface{}); ok {
		redisConfigs = redisConfigsInterface
	} else if redisConfigsInterfaceMap, ok := config["redis"].(map[interface{}]interface{}); ok {
		// 转换 map[interface{}]interface{} 到 map[string]interface{}
		redisConfigs = make(map[string]interface{})
		for k, v := range redisConfigsInterfaceMap {
			if strKey, ok := k.(string); ok {
				redisConfigs[strKey] = v
			}
		}
	} else {
		return fmt.Errorf("redis config not found")
	}

	// 获取具体的 Redis 配置
	var redisConfig map[string]interface{}
	if redisConfigInterface, ok := redisConfigs[tagInfo.Name].(map[string]interface{}); ok {
		redisConfig = redisConfigInterface
	} else if redisConfigInterfaceMap, ok := redisConfigs[tagInfo.Name].(map[interface{}]interface{}); ok {
		// 转换 map[interface{}]interface{} 到 map[string]interface{}
		redisConfig = make(map[string]interface{})
		for k, v := range redisConfigInterfaceMap {
			if strKey, ok := k.(string); ok {
				redisConfig[strKey] = v
			}
		}
	} else {
		return fmt.Errorf("redis config %s not found", tagInfo.Name)
	}

	// 创建Redis客户端
	client := redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%v:%v", redisConfig["host"], redisConfig["port"]),
		Password: fmt.Sprintf("%v", redisConfig["password"]),
		DB:       int(redisConfig["db"].(int)),
	})

	field.Set(reflect.ValueOf(client))
	return nil
}

// bindGormDB 绑定GORM数据库连接
func (cb *ComboBuilder) bindGormDB(field reflect.Value, tagInfo ConfxTag, config map[string]interface{}) error {
	// 尝试获取 mysql 配置，支持多种类型
	var mysqlConfigs map[string]interface{}

	if mysqlConfigsInterface, ok := config["mysql"].(map[string]interface{}); ok {
		mysqlConfigs = mysqlConfigsInterface
	} else if mysqlConfigsInterfaceMap, ok := config["mysql"].(map[interface{}]interface{}); ok {
		// 转换 map[interface{}]interface{} 到 map[string]interface{}
		mysqlConfigs = make(map[string]interface{})
		for k, v := range mysqlConfigsInterfaceMap {
			if strKey, ok := k.(string); ok {
				mysqlConfigs[strKey] = v
			}
		}
	} else {
		return fmt.Errorf("mysql config not found")
	}

	// 获取具体的 MySQL 配置
	var mysqlConfig map[string]interface{}
	if mysqlConfigInterface, ok := mysqlConfigs[tagInfo.Name].(map[string]interface{}); ok {
		mysqlConfig = mysqlConfigInterface
	} else if mysqlConfigInterfaceMap, ok := mysqlConfigs[tagInfo.Name].(map[interface{}]interface{}); ok {
		// 转换 map[interface{}]interface{} 到 map[string]interface{}
		mysqlConfig = make(map[string]interface{})
		for k, v := range mysqlConfigInterfaceMap {
			if strKey, ok := k.(string); ok {
				mysqlConfig[strKey] = v
			}
		}
	} else {
		return fmt.Errorf("mysql config %s not found", tagInfo.Name)
	}

	// 构建DSN
	dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=%v&parseTime=True&loc=Local",
		mysqlConfig["username"],
		mysqlConfig["password"],
		mysqlConfig["host"],
		mysqlConfig["port"],
		mysqlConfig["database"],
		mysqlConfig["charset"],
	)

	// 创建GORM数据库连接
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return fmt.Errorf("failed to connect to database: %v", err)
	}

	field.Set(reflect.ValueOf(db))
	return nil
}

// bindJSONConfig 绑定JSON配置
func (cb *ComboBuilder) bindJSONConfig(field reflect.Value, fieldType reflect.StructField, tagInfo ConfxTag, config map[string]interface{}) error {
	// 尝试获取 config 配置，支持多种类型
	var configSection map[string]interface{}

	if configSectionInterface, ok := config["config"].(map[string]interface{}); ok {
		configSection = configSectionInterface
	} else if configSectionInterfaceMap, ok := config["config"].(map[interface{}]interface{}); ok {
		// 转换 map[interface{}]interface{} 到 map[string]interface{}
		configSection = make(map[string]interface{})
		for k, v := range configSectionInterfaceMap {
			if strKey, ok := k.(string); ok {
				configSection[strKey] = v
			}
		}
	} else {
		return fmt.Errorf("config section not found")
	}

	// 获取具体的字段配置
	var fieldConfig map[string]interface{}
	if fieldConfigInterface, ok := configSection[fieldType.Name].(map[string]interface{}); ok {
		fieldConfig = fieldConfigInterface
	} else if fieldConfigInterfaceMap, ok := configSection[fieldType.Name].(map[interface{}]interface{}); ok {
		// 转换 map[interface{}]interface{} 到 map[string]interface{}
		fieldConfig = make(map[string]interface{})
		for k, v := range fieldConfigInterfaceMap {
			if strKey, ok := k.(string); ok {
				fieldConfig[strKey] = v
			}
		}
	} else {
		return fmt.Errorf("config %s not found", fieldType.Name)
	}

	// 创建新的结构体实例
	newInstance := reflect.New(fieldType.Type.Elem())
	newStruct := newInstance.Elem()
	newType := newStruct.Type()

	// 填充字段
	for i := 0; i < newStruct.NumField(); i++ {
		structField := newStruct.Field(i)
		structFieldType := newType.Field(i)

		// 获取JSON标签或使用字段名
		jsonTag := structFieldType.Tag.Get("json")
		fieldName := structFieldType.Name
		if jsonTag != "" {
			fieldName = jsonTag
		}

		if value, exists := fieldConfig[fieldName]; exists {
			if structField.CanSet() {
				structField.SetString(fmt.Sprintf("%v", value))
			}
		}
	}

	field.Set(newInstance)
	return nil
}
